//
// Created by yorkc on 2023/12/4.
//

#include <sstream>
#include <map>
#include "WSqlite.h"

using namespace std;

WSqlite::WSqlite() {
    db = nullptr;
}

WSqlite::~WSqlite() {
    Destory();
}

void WSqlite::Destory() {
    if (db) {
        sqlite3_close(db);
        db = nullptr;
    }
}

static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
    int i;

    for (i = 0; i < argc; i++) {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}

int WSqlite::CreateDbFile(const string &path) {
    return sqlite3_open(path.c_str(), &db);
}

int WSqlite::CreateTable(const string &table_name, const string feild_def) {
    stringstream createsql;
    createsql << "CREATE TABLE  " << table_name << "(" << feild_def << ");";
    char *errms = NULL;
    int result;
    result = sqlite3_exec(db, createsql.str().c_str(), callback, 0, &errms);
    if (result != SQLITE_OK) {
        //二级指针的对应数据必须释放掉
        sqlite3_free(errms);
    }
    return result;
}

int WSqlite::DropTable(const string &table_name) {
    stringstream fmt;
    int status;
    char *errmsg = NULL;
    fmt << "DELETE FROM " << table_name << ";";
    status = sqlite3_exec(db, fmt.str().c_str(), callback, 0, &errmsg);
    if (status != SQLITE_OK) {
        sqlite3_free(errmsg);
    }
    return status;
}


int WSqlite::Opendb(const string &path) {
    return sqlite3_open(path.c_str(), &db);
}

int WSqlite::Insert(const string &sqlInsert) {
    char *errmsg = NULL;
    int status;
    status = sqlite3_exec(db, sqlInsert.c_str(), callback, 0, &errmsg);
    if (status != SQLITE_OK) {
        fprintf(stderr, "sqlite insert error:%s\n", errmsg);
        sqlite3_free(errmsg);
    }
    return status;
}

int WSqlite::Delete(const string &sqlDelete) {
    int nCols = 0;
    int nRows = 0;
    char **azResult = NULL;
    char *errMsg = NULL;
    int res = sqlite3_get_table(db, sqlDelete.c_str(), &azResult, &nRows, &nCols, &errMsg);
    if (azResult) {
        sqlite3_free_table(azResult);
    }
    if (errMsg) {
        sqlite3_free(errMsg);
    }
    return res;
}

int WSqlite::Update(const string &sqlUpdate) {
    char *zErrMsg = NULL;
    int ret = sqlite3_exec(db, sqlUpdate.c_str(), NULL, NULL, &zErrMsg);
    if (zErrMsg) {
        sqlite3_free(zErrMsg);
    }
    return ret;
}

int WSqlite::QueryData(const string &sqlQuery, vector<string> &colnames, vector<vector<string>> &datas) {
    char **resultstr = NULL;
    char *errmsg = NULL;
    int rowsize = 0;
    int colsize = 0;
    cout << "query sql:" << sqlQuery.c_str() << endl;
    int result = sqlite3_get_table(db, sqlQuery.c_str(), &resultstr, &rowsize, &colsize, &errmsg);
    colnames.clear();
    colnames.reserve(colsize);
    datas.clear();
    datas.reserve(rowsize);
    cout << "query result,rowsize:" << rowsize << ",colsize:" << colsize << endl;
    //表头
    for (int header = 0; header < colsize; ++header) {
        cout << resultstr[header] << "\t";
        colnames.push_back(resultstr[header]);
    }
    cout << endl;


    //查询结果，它依然一维数组（不要以为是二维数组，更不要以为是三维数组,它把一个二维的表（传统的行列表示法）用一个扁平的形式来表示。
    int cellIndex = colsize;
    for (int i = 1; i <= rowsize; ++i) {
        vector<string> rowdatas;
        for (int j = 0; j < colsize; ++j) {
            char *rowdata = resultstr[cellIndex];
            rowdatas.push_back(rowdata);
            /* int cell = i * colsize + j;
             cout << resultstr[cell] << "\t";*/
            cellIndex++;
        }
        cout << endl;
        datas.push_back(rowdatas);
    }
    if (resultstr) {
        //指针非空，释放返回查询内容的指针数组
        sqlite3_free_table(resultstr);
    }
    if (errmsg) {
        sqlite3_free(errmsg);
    }
    return result;
}

int WSqlite::QueryDataToMap(const string &sqlQuery, vector<map<std::string, std::string>> &results) {
    char **resultstr = NULL;
    char *errmsg = NULL;
    int rowsize = 0;
    int colsize = 0;
    cout << "query sql:" << sqlQuery.c_str() << endl;
    int result = sqlite3_get_table(db, sqlQuery.c_str(), &resultstr, &rowsize, &colsize, &errmsg);
    vector<string> colnames;
    colnames.reserve(colsize);
    cout << "query result,rowsize:" << rowsize << ",colsize:" << colsize << endl;
    //表头
    for (int header = 0; header < colsize; ++header) {
        cout << resultstr[header] << "\t";
        colnames.push_back(resultstr[header]);
    }
    cout << endl;
    int cellIndex = colsize;
    for (int rowindex = 1; rowindex <= rowsize; ++rowindex) {
        map<string, string> rowmap;
        for (int colindex = 0; colindex < colsize; ++colindex) {
            char *rowdata = resultstr[cellIndex];
            /*
            cout<<"rowdata:"<<rowdata;
            int cell = rowindex * colsize + colindex;
            rowmap.insert(make_pair(colnames[colindex], rowdata));
            cout << resultstr[cell] << "\t";*/
            const pair<const string, string> &pair = map<string, string>::value_type(colnames[colindex], rowdata);
            //每个行键值对，k:字段，v:字段值
            rowmap.insert(pair);
            cellIndex++;
        }
        cout << endl;
        results.push_back(rowmap);
    }
    cout << "query results:" << results.size() << endl;
    if (resultstr) {
        //指针非空，释放返回查询内容的指针数组
        sqlite3_free_table(resultstr);
    }
    if (errmsg) {
        sqlite3_free(errmsg);
    }
    return result;
}

int WSqlite::QueryDataWithC() {
    char **resultstr = NULL;
    char *errmsg = NULL;
    int rowsize;//行数
    int colsize;//列数
    int result;
    char sqlQuery[500];
    sprintf(sqlQuery, "SELECT * FROM PROTOC_SETTING WHERE DeviceType=%d AND DeviceModel=%s", 1, "zhouyu");
    printf("----------- sqlite3_exec sqlite3_get_table sql: %s\n", sqlQuery);
    result = sqlite3_get_table(db, sqlQuery, &resultstr, &rowsize, &colsize, &errmsg);
    if (result || errmsg) {
        sqlite3_free(errmsg);
        sqlite3_close(db);
        perror("----------- sqlite3_exec sqlite3_get_table error-----------\n");
    } else {
        if (resultstr && rowsize > 0 && colsize > 0) {
            for (int row = 1; row <= rowsize; ++row) {
                for (int col = 0; col < colsize; ++col) {
                    int cell = row * colsize + col;
                    char *rowdata = resultstr[cell];
                }
            }
        }
    }
    return 0;
}

template<typename E>
E WSqlite::QueryData2(const string &sqlQuery, E entity) {

    return nullptr;
}

